package com.luqili.utils.pub.date;

import com.luqili.utils.pub.base.LuException;
import com.luqili.utils.pub.link.Pair;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

/**
 * 扩展日期工具类
 *
 * @author luqili 2016年12月12日
 */
public class DateUtilsExt {
    /**
     * 反序列化格式
     * <p>
     * 不允许修改
     * </p>
     */
    public static final String[] DEFAULT_PARSE_PATTERNS = {"yyyyMMdd", "yyyy-MM-dd", "yyyy年MM月dd日", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss"};

    /**
     * 通过时间戳重新加载日期类型
     *
     * @param date
     * @return
     */
    public static Date reloadDate(Date date) {
        if (date != null) {
            date = new Date(date.getTime());
        }
        return date;
    }

    /**
     * 获得当前时间
     *
     * @return
     */
    public static Date getToday() {
        return new Date();
    }

    /**
     * 获得今天的时间，单位天
     *
     * @return
     */
    public static Date getTodayTruncateDay() {
        return DateUtils.truncate(getToday(), Calendar.DATE);
    }

    /**
     * 截短为天
     *
     * @param date
     * @return
     */
    public static Date truncateDate(Date date) {
        return DateUtils.truncate(date, Calendar.DATE);
    }


    /**
     * 获得指定日期当前的开始时间 即 00:00:00
     *
     * @param date
     * @param addDays
     * @return
     */
    public static Date getStartDay(Date date, int addDays) {
        if (addDays != 0) {
            date = DateUtils.addDays(date, addDays);
        }
        return DateUtils.truncate(date, Calendar.DATE);
    }

    /**
     * 获得指定日期当前的结束时间 即 23:59:59
     *
     * @param date    指定日期
     * @param addDays 增加天数
     * @return
     */
    public static Date getEndDay(Date date, int addDays) {
        Date d1 = DateUtils.truncate(date, Calendar.DATE);
        Date d2 = DateUtils.addDays(d1, addDays + 1);
        return DateUtils.addMilliseconds(d2, -1);
    }

    /**
     * 获得指定日期当前的结束时间 即 23:59:59
     *
     * @param date 指定日期
     * @return
     */
    public static Date getEndDay(Date date) {
        return getEndDay(date, 0);
    }


    /**
     * 根据字符串自动转换日期
     *
     * @param str
     * @return 失败返回null
     */
    public static Date parseDate(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return DateUtils.parseDate(str, DEFAULT_PARSE_PATTERNS);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 根据字符串自动转换日期
     *
     * @param str
     * @param parsePatterns
     * @return 失败返回null
     */
    public static Date parseDate(String str, String... parsePatterns) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return DateUtils.parseDate(str, parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 格式化日期
     *
     * @param str
     * @param parsePatterns
     * @return 失败返回null
     */
    public static Date parseDateCN(final String str, final String... parsePatterns) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return DateUtils.parseDate(str, Locale.CHINA, parsePatterns);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 计算两个日期相差
     *
     * @param d1
     * @param d2
     * @param unit <li>d1 -d2
     * @return
     */
    public static long differ(Date d1, Date d2, long unit) {
        long differ = d1.getTime() - d2.getTime();
        return differ / unit;
    }

    /**
     * 计算两个日期相差的天数
     *
     * @param d1
     * @param d2 <li>d1 -d2
     * @return
     */
    public static int differDay(Date d1, Date d2) {
        return (int) differ(d1, d2, DateUtils.MILLIS_PER_DAY);
    }

    /**
     * 计算两个日期相差的月份
     *
     * @param d1
     * @param d2 <li>d1 -d2
     * @return
     */
    public static int differMonth(Date d1, Date d2) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d1);
        int year_1 = calendar.get(Calendar.YEAR);
        int month_1 = calendar.get(Calendar.MONTH);
        calendar.setTime(d2);
        int year_2 = calendar.get(Calendar.YEAR);
        int month_2 = calendar.get(Calendar.MONTH);
        return (year_1 - year_2) * 12 + (month_1 - month_2);
    }

    /**
     * 计算两个日期相差的年份
     *
     * @param d1
     * @param d2 <li>d1 -d2
     * @return
     */
    public static int differYear(Date d1, Date d2) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d1);
        int year_1 = calendar.get(Calendar.YEAR);
        calendar.setTime(d2);
        int year_2 = calendar.get(Calendar.YEAR);
        return year_1 - year_2;
    }

    /**
     * 计算人的年龄
     *
     * <pre>
     * DateUtilsExt.getPeopleAge(DateUtilsExt.parseDate("20190911"),DateUtilsExt.parseDate("20100215")) = 9
     * DateUtilsExt.getPeopleAge(DateUtilsExt.parseDate("20190911"),DateUtilsExt.parseDate("20100910")) = 9
     * DateUtilsExt.getPeopleAge(DateUtilsExt.parseDate("20190911"),DateUtilsExt.parseDate("20100915")) = 8
     * DateUtilsExt.getPeopleAge(DateUtilsExt.parseDate("20190911"),DateUtilsExt.parseDate("20100911")) = 9
     * DateUtilsExt.getPeopleAge(DateUtilsExt.parseDate("20190911"),DateUtilsExt.parseDate("20000911")) = 19
     *
     * </pre>
     *
     * @param now      当前日期
     * @param birthday 生日
     * @return
     */
    public static int getPeopleAge(Date now, Date birthday) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(now);

        int year1 = calendar.get(Calendar.YEAR);
        int month1 = calendar.get(Calendar.MONTH);
        int day1 = calendar.get(Calendar.DAY_OF_MONTH);

        calendar.setTime(birthday);
        int year2 = calendar.get(Calendar.YEAR);
        int month2 = calendar.get(Calendar.MONTH);
        int day2 = calendar.get(Calendar.DAY_OF_MONTH);

        int age = year1 - year2;
        if (month1 < month2) {
            age--;
        } else if (month1 == month2) {
            if (day1 < day2) {
                age--;
            }
        }
        return age;
    }

    /**
     * 日期 src 是否在 start 与 end之间
     *
     * @param src
     * @param start
     * @param end
     * @return
     */
    public static boolean between(Date src, Date start, Date end) {
        boolean result = false;
        if (src == null || start == null || end == null) {
            result = false;
        } else {
            result = src.getTime() >= start.getTime() && src.getTime() <= end.getTime();
        }
        return result;
    }

    /**
     * 统一处理查询时间
     *
     * @param startDateStr 为空时默认当日凌晨
     * @param endDateStr   为空时默认当日最后一秒的时间
     * @return
     */
    public static Pair<Date, Date> handSearchDate(String startDateStr, String endDateStr) {
        String[] formatDate = {"yyyy-MM-dd", "yyyy-MM-dd HH:mm"};
        Date startDate = null;
        Date endDate = null;
        if (StringUtils.isNotBlank(startDateStr)) {
            try {
                startDate = DateUtils.parseDate(startDateStr, formatDate);
            } catch (ParseException e) {
                throw new RuntimeException("开始时间格式错误");
            }
        }
        if (StringUtils.isNotBlank(endDateStr)) {
            try {
                endDate = DateUtils.parseDate(endDateStr, formatDate);
            } catch (ParseException e) {
                throw new RuntimeException("结束时间格式错误");
            }
        }
        if (startDate == null) {
            startDate = DateUtils.truncate(new Date(), Calendar.DATE);
        }
        if (endDate == null) {
            endDate = DateUtils.addDays(startDate, 1);
            endDate = DateUtils.addMilliseconds(endDate, -1);
        }
        long dv = endDate.getTime() - startDate.getTime();
        if (dv < 0) {
            throw new RuntimeException("开始时间不能大于结束时间");
        }
        return new Pair<Date, Date>(startDate, endDate);
    }

    /**
     * 获得最大的日期
     *
     * <pre>
     * DateUtils.maxDate(null,null) = null
     * DateUtils.maxDate(DateUtils.parseDate("20190911"),null) = d1
     * DateUtils.maxDate(null,DateUtils.parseDate("20190911")) = d2
     * DateUtils.maxDate(DateUtils.parseDate("20190911"),DateUtils.parseDate("20100915")) = d1
     * </pre>
     *
     * @param d1
     * @param d2
     * @return
     */
    public static Date maxDate(Date d1, Date d2) {
        if (d1 == null) {
            return d2;
        } else if (d2 == null) {
            return d1;
        }
        return d1.compareTo(d2) > 0 ? d1 : d2;
    }

    /**
     * 合并日期和时间
     *
     * @param date 取日期部分
     * @param time 取时间部分
     * @return
     */
    public static Date mergeDateTime(Date date, Date time) {
        String str = DateFormatUtils.format(date, "yyyyMMdd") + DateFormatUtils.format(time, "HHmmss");
        return parseDateCN(str, "yyyyMMddHHmmss");
    }

    /**
     * 当前时间大于指定时间 过去的时间
     *
     * @param dateTime
     * @return
     */
    public static boolean currentTimeThan(Date dateTime) {
        if (dateTime == null) {
            throw new LuException("比较时间不能为空");
        }
        return System.currentTimeMillis() > dateTime.getTime();
    }

    /**
     * 当前时间小于指定时间，未来的时间
     *
     * @param dateTime
     * @return
     */
    public static boolean currentTimeLessThan(Date dateTime) {
        if (dateTime == null) {
            throw new LuException("比较时间不能为空");
        }
        return System.currentTimeMillis() < dateTime.getTime();
    }
}
